home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gamers Delight 2
/
Gamers Delight 2.iso
/
Aminet
/
game
/
role
/
Ang261Lib.lha
/
src
/
save.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-22
|
48KB
|
1,879 lines
/*
* save.c: save and restore games and monster memory info
*
* Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
*
* This software may be copied and distributed for educational, research, and
* not for profit purposes provided that this copyright and statement are
* included in all such copies.
*/
#include <stdio.h>
#include "constant.h"
#include "config.h"
#include "types.h"
#include "externs.h"
#include "monster.h"
#ifndef USG
/* stuff only needed for Berkeley UNIX */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/param.h>
#endif
#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#include <fcntl.h>
#else
#include "string.h"
#endif
#else
#include <strings.h>
#endif
#ifdef __MINT__
#include <stat.h> /* chmod() */
#endif
/* Lets do all prototypes correctly.... -CWS */
#ifndef NO_LINT_ARGS
static int sv_write();
static void wr_byte();
static void wr_short();
static void wr_long();
static void wr_bytes();
static void wr_string();
static void wr_shorts();
static void wr_item();
static void wr_monster();
static void rd_byte();
static void rd_short();
static void rd_long();
static void rd_bytes();
static void rd_string();
static void rd_shorts();
static void rd_item();
static void rd_monster();
#endif
#if !defined(ATARIST_MWC)
#ifdef MAC
#include <time.h>
#else
long time();
#endif
#else
char *malloc();
#endif
#ifndef SET_UID
#include <sys/stat.h>
#endif
/*
* these are used for the save file, to avoid having to pass them to every
* procedure
*/
static FILE *fileptr;
static int8u xor_byte;
static int from_savefile; /* can overwrite old savefile when save */
static int32u start_time; /* time that play started */
static int8u version_maj, version_min, patch_level;
/*
* This save package was brought to by -JWT- and
* RAK- and has been completely rewritten for UNIX by -JEW-
*/
/* and has been completely rewritten again by -CJS- */
/* and completely rewritten again! for portability by -JEW- */
static char *
basename(a)
char *a;
{
char *b;
char *strrchr();
if ((b = strrchr(a, (int)'/')) == (char *)0)
return a;
return b;
}
static void
wr_unique(item)
register struct unique_mon *item;
{
wr_long((int32u) item->exist);
wr_long((int32u) item->dead);
}
static void
rd_unique(item)
register struct unique_mon *item;
{
rd_long((int32u *) & item->exist);
rd_long((int32u *) & item->dead);
}
static int
sv_write()
{
int32u l;
register int i, j;
int count;
int8u char_tmp, prev_char;
register cave_type *c_ptr;
register recall_type *r_ptr;
struct stats *s_ptr;
#ifdef MSDOS
inven_type *t_ptr;
#endif
register struct flags *f_ptr;
store_type *st_ptr;
struct misc *m_ptr;
/* clear the death flag when creating a HANGUP save file, so that player can
* see tombstone when restart
*/
if (eof_flag)
death = FALSE;
l = 0;
if (find_cut)
l |= 1;
if (find_examine)
l |= 2;
if (find_prself)
l |= 4;
if (find_bound)
l |= 8;
if (prompt_carry_flag)
l |= 16;
if (rogue_like_commands)
l |= 32;
if (show_weight_flag)
l |= 64;
if (highlight_seams)
l |= 128;
if (find_ignore_doors)
l |= 0x100L;
if (no_haggle_flag)
l |= 0x200L;
if (!carry_query_flag)
l |= 0x400L;
if (unfelt)
l |= 0x0001000L;
if (delay_spd > 10)
delay_spd = 10; /* bounds for delay_speed -CWS */
if (delay_spd < 0)
delay_spd = 0;
l |= ((delay_spd & 0xf) << 13);
l |= ((hitpoint_warn & 0xf) << 17);
if (plain_descriptions) /* don't do "black Mushroom of Curing" -CWS */
l |= 0x00400000L;
if (show_equip_weight_flag)
l |= 0x00800000L;
if (feeling > 10)
feeling = 0; /* bounds for level feelings -CWS */
if (feeling < 0)
feeling = 0;
l |= ((feeling & 0xf) << 24);
if (equippy_chars) /* equippy chars option -CWS */
l |= 0x20000000L;
if (quick_messages) /* quick messages option -CWS */
l |= 0x40000000L;
if (death)
l |= 0x80000000L; /* Sign bit */
wr_long(GROND);
wr_long(RINGIL);
wr_long(AEGLOS);
wr_long(ARUNRUTH);
wr_long(MORMEGIL);
wr_long(ANGRIST);
wr_long(GURTHANG);
wr_long(CALRIS);
wr_long(ANDURIL);
wr_long(STING);
wr_long(ORCRIST);
wr_long(GLAMDRING);
wr_long(DURIN);
wr_long(AULE);
wr_long(THUNDERFIST);
wr_long(BLOODSPIKE);
wr_long(DOOMCALLER);
wr_long(NARTHANC);
wr_long(NIMTHANC);
wr_long(DETHANC);
wr_long(GILETTAR);
wr_long(RILIA);
wr_long(BELANGIL);
wr_long(BALLI);
wr_long(LOTHARANG);
wr_long(FIRESTAR);
wr_long(ERIRIL);
wr_long(CUBRAGOL);
wr_long(BARD);
wr_long(COLLUIN);
wr_long(HOLCOLLETH);
wr_long(TOTILA);
wr_long(PAIN);
wr_long(ELVAGIL);
wr_long(AGLARANG);
wr_long(EORLINGAS);
wr_long(BARUKKHELED);
wr_long(WRATH);
wr_long(HARADEKKET);
wr_long(MUNDWINE);
wr_long(GONDRICAM);
wr_long(ZARCUTHRA);
wr_long(CARETH);
wr_long(FORASGIL);
wr_long(CRISDURIAN);
wr_long(COLANNON);
wr_long(HITHLOMIR);
wr_long(THALKETTOTH);
wr_long(ARVEDUI);
wr_long(THRANDUIL);
wr_long(THENGEL);
wr_long(HAMMERHAND);
wr_long(CELEGORM);
wr_long(THROR);
wr_long(MAEDHROS);
wr_long(OLORIN);
wr_long(ANGUIREL);
wr_long(OROME);
wr_long(EONWE);
wr_long(THEODEN);
wr_long(ULMO);
wr_long(OSONDIR);
wr_long(TURMIL);
wr_long(CASPANION);
wr_long(TIL);
wr_long(DEATHWREAKER);
wr_long(AVAVIR);
wr_long(TARATOL);
wr_long(DOR_LOMIN);
wr_long(NENYA);
wr_long(NARYA);
wr_long(VILYA);
wr_long(BELEGENNON);
wr_long(FEANOR);
wr_long(ISILDUR);
wr_long(SOULKEEPER);
wr_long(FINGOLFIN);
wr_long(ANARION);
wr_long(POWER);
wr_long(PHIAL);
wr_long(BELEG);
wr_long(DAL);
wr_long(PAURHACH);
wr_long(PAURNIMMEN);
wr_long(PAURAEGEN);
wr_long(PAURNEN);
wr_long(CAMMITHRIM);
wr_long(CAMBELEG);
wr_long(INGWE);
wr_long(CARLAMMAS);
wr_long(HOLHENNETH);
wr_long(AEGLIN);
wr_long(CAMLOST);
wr_long(NIMLOTH);
wr_long(NAR);
wr_long(BERUTHIEL);
wr_long(GORLIM);
wr_long(ELENDIL);
wr_long(THORIN);
wr_long(CELEBORN);
wr_long(THRAIN);
wr_long(GONDOR);
wr_long(THINGOL);
wr_long(THORONGIL);
wr_long(LUTHIEN);
wr_long(TUOR);
wr_long(ROHAN);
wr_long(TULKAS);
wr_long(NECKLACE);
wr_long(BARAHIR);
wr_long(RAZORBACK);
wr_long(BLADETURNER);
for (i = 0; i < MAX_QUESTS; i++)
wr_long(quests[i]);
for (i = 0; i < MAX_CREATURES; i++)
wr_unique(&u_list[i]);
for (i = 0; i < MAX_CREATURES; i++) {
r_ptr = &c_recall[i];
if (r_ptr->r_cmove || r_ptr->r_cdefense || r_ptr->r_kills ||
r_ptr->r_spells2 || r_ptr->r_spells3 || r_ptr->r_spells ||
r_ptr->r_deaths || r_ptr->r_attacks[0] || r_ptr->r_attacks[1] ||
r_ptr->r_attacks[2] || r_ptr->r_attacks[3]) {
wr_short((int16u) i);
wr_long(r_ptr->r_cmove);
wr_long(r_ptr->r_spells);
wr_long(r_ptr->r_spells2);
wr_long(r_ptr->r_spells3);
wr_short(r_ptr->r_kills);
wr_short(r_ptr->r_deaths);
wr_long(r_ptr->r_cdefense);
wr_byte(r_ptr->r_wake);
wr_byte(r_ptr->r_ignore);
wr_bytes(r_ptr->r_attacks, MAX_MON_NATTACK);
}
}
wr_short((int16u) 0xFFFF); /* sentinel to indicate no more monster info */
wr_short((int16u) log_index);
wr_long(l);
wr_long(l); /* added some duplicates, for future flags expansion -CWS */
wr_long(l);
wr_long(l);
m_ptr = &py.misc;
wr_string(m_ptr->name);
wr_byte(m_ptr->male);
wr_long((int32u) m_ptr->au);
wr_long((int32u) m_ptr->max_exp);
wr_long((int32u) m_ptr->exp);
wr_short(m_ptr->exp_frac);
wr_short(m_ptr->age);
wr_short(m_ptr->ht);
wr_short(m_ptr->wt);
wr_short(m_ptr->lev);
wr_short(m_ptr->max_dlv);
wr_short((int16u) m_ptr->srh);
wr_short((int16u) m_ptr->fos);
wr_short((int16u) m_ptr->bth);
wr_short((int16u) m_ptr->bthb);
wr_short((int16u) m_ptr->mana);
wr_short((int16u) m_ptr->mhp);
wr_short((int16u) m_ptr->ptohit);
wr_short((int16u) m_ptr->ptodam);
wr_short((int16u) m_ptr->pac);
wr_short((int16u) m_ptr->ptoac);
wr_short((int16u) m_ptr->dis_th);
wr_short((int16u) m_ptr->dis_td);
wr_short((int16u) m_ptr->dis_ac);
wr_short((int16u) m_ptr->dis_tac);
wr_short((int16u) m_ptr->disarm);
wr_short((int16u) m_ptr->save);
wr_short((int16u) m_ptr->sc);
wr_short((int16u) m_ptr->stl);
wr_byte(m_ptr->pclass);
wr_byte(m_ptr->prace);
wr_byte(m_ptr->hitdie);
wr_byte(m_ptr->expfact);
wr_short((int16u) m_ptr->cmana);
wr_short(m_ptr->cmana_frac);
wr_short((int16u) m_ptr->chp);
wr_short(m_ptr->chp_frac);
for (i = 0; i < 4; i++)
wr_string(m_ptr->history[i]);
s_ptr = &py.stats;
wr_shorts(s_ptr->max_stat, 6);
wr_bytes(s_ptr->cur_stat, 6); /* Was wr_shorts -TL */
wr_shorts((int16u *) s_ptr->mod_stat, 6);
wr_shorts(s_ptr->use_stat, 6);
f_ptr = &py.flags;
wr_long(f_ptr->status);
wr_short((int16u) f_ptr->rest);
wr_short((int16u) f_ptr->blind);
wr_short((int16u) f_ptr->paralysis);
wr_short((int16u) f_ptr->confused);
wr_short((int16u) f_ptr->food);
wr_short((int16u) f_ptr->food_digested);
wr_short((int16u) f_ptr->protection);
wr_short((int16u) f_ptr->speed);
wr_short((int16u) f_ptr->fast);
wr_short((int16u) f_ptr->slow);
wr_short((int16u) f_ptr->afraid);
wr_short((int16u) f_ptr->cut);
wr_short((int16u) f_ptr->stun);
wr_short((int16u) f_ptr->poisoned);
wr_short((int16u) f_ptr->image);
wr_short((int16u) f_ptr->protevil);
wr_short((int16u) f_ptr->invuln);
wr_short((int16u) f_ptr->hero);
wr_short((int16u) f_ptr->shero);
wr_short((int16u) f_ptr->shield);
wr_short((int16u) f_ptr->blessed);
wr_short((int16u) f_ptr->resist_heat);
wr_short((int16u) f_ptr->resist_cold);
wr_short((int16u) f_ptr->resist_acid);
wr_short((int16u) f_ptr->resist_light);
wr_short((int16u) f_ptr->resist_poison);
wr_short((int16u) f_ptr->detect_inv);
wr_short((int16u) f_ptr->word_recall);
wr_short((int16u) f_ptr->see_infra);
wr_short((int16u) f_ptr->tim_infra);
wr_byte(f_ptr->see_inv);
wr_byte(f_ptr->teleport);
wr_byte(f_ptr->free_act);
wr_byte(f_ptr->slow_digest);
wr_byte(f_ptr->aggravate);
wr_byte(f_ptr->fire_resist);
wr_byte(f_ptr->cold_resist);
wr_byte(f_ptr->acid_resist);
wr_byte(f_ptr->regenerate);
wr_byte(f_ptr->lght_resist);
wr_byte(f_ptr->ffall);
wr_byte(f_ptr->sustain_str);
wr_byte(f_ptr->sustain_int);
wr_byte(f_ptr->sustain_wis);
wr_byte(f_ptr->sustain_con);
wr_byte(f_ptr->sustain_dex);
wr_byte(f_ptr->sustain_chr);
wr_byte(f_ptr->confuse_monster);
wr_byte(f_ptr->new_spells);
wr_byte(f_ptr->poison_resist);
wr_byte(f_ptr->hold_life);
wr_byte(f_ptr->telepathy);
wr_byte(f_ptr->fire_im);
wr_byte(f_ptr->acid_im);
wr_byte(f_ptr->poison_im);
wr_byte(f_ptr->cold_im);
wr_byte(f_ptr->light_im);
wr_byte(f_ptr->light);
wr_byte(f_ptr->confusion_resist);
wr_byte(f_ptr->sound_resist);
wr_byte(f_ptr->light_resist);
wr_byte(f_ptr->dark_resist);
wr_byte(f_ptr->chaos_resist);
wr_byte(f_ptr->disenchant_resist);
wr_byte(f_ptr->shards_resist);
wr_byte(f_ptr->nexus_resist);
wr_byte(f_ptr->blindness_resist);
wr_byte(f_ptr->nether_resist);
wr_byte(f_ptr->fear_resist); /* added -CWS */
wr_short((int16u) missile_ctr);
wr_long((int32u) turn);
wr_long((int32u) old_turn); /* added -CWS */
wr_short((int16u) inven_ctr);
for (i = 0; i < inven_ctr; i++)
wr_item(&inventory[i]);
for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++)
wr_item(&inventory[i]);
wr_short((int16u) inven_weight);
wr_short((int16u) equip_ctr);
wr_long(spell_learned);
wr_long(spell_worked);
wr_long(spell_forgotten);
wr_long(spell_learned2);
wr_long(spell_worked2);
wr_long(spell_forgotten2);
wr_bytes(spell_order, 64);
wr_bytes(object_ident, OBJECT_IDENT_SIZE);
wr_long(randes_seed);
wr_long(town_seed);
wr_short((int16u) last_msg);
for (i = 0; i < MAX_SAVE_MSG; i++)
wr_string(old_msg[i]);
/* this indicates 'cheating' if it is a one */
wr_short((int16u) panic_save);
wr_short((int16u) total_winner);
wr_short((int16u) noscore);
wr_shorts(player_hp, MAX_PLAYER_LEVEL);
for (i = 0; i < MAX_STORES; i++) {
st_ptr = &store[i];
wr_long((int32u) st_ptr->store_open);
wr_short((int16u) st_ptr->insult_cur);
wr_byte(st_ptr->owner);
wr_byte(st_ptr->store_ctr);
wr_short(st_ptr->good_buy);
wr_short(st_ptr->bad_buy);
for (j = 0; j < st_ptr->store_ctr; j++) {
wr_long((int32u) st_ptr->store_inven[j].scost);
wr_item(&st_ptr->store_inven[j].sitem);
}
}
/* save the current time in the savefile */
l = time((long *)0);
/* if (l < start_time) { someone is messing with the clock!, assume that we
* have been playing for 1 day l = start_time + 86400L; }
*/
wr_long(l);
/* starting with 5.2, put died_from string in savefile */
wr_string(died_from);
/* only level specific info follows, this allows characters to be
* resurrected, the dungeon level info is not needed for a resurrection
*/
if (death) {
if (ferror(fileptr) || fflush(fileptr) == EOF)
return FALSE;
return TRUE;
}
wr_short((int16u) dun_level);
wr_short((int16u) char_row);
wr_short((int16u) char_col);
wr_short((int16u) mon_tot_mult);
wr_short((int16u) cur_height);
wr_short((int16u) cur_width);
wr_short((int16u) max_panel_rows);
wr_short((int16u) max_panel_cols);
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++) {
c_ptr = &cave[i][j];
if (c_ptr->cptr != 0) {
wr_byte((int8u) i);
wr_byte((int8u) j);
wr_short((int16u) c_ptr->cptr); /* was wr_byte -CWS */
}
}
wr_byte((int8u) 0xFF); /* marks end of cptr info */
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++) {
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0) {
wr_byte((int8u) i);
wr_byte((int8u) j);
wr_short((int16u) c_ptr->tptr);
}
}
wr_byte(0xFF); /* marks end of tptr info */
/* must set counter to zero, note that code may write out two bytes
* unnecessarily
*/
count = 0;
prev_char = 0;
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++) {
c_ptr = &cave[i][j];
char_tmp = c_ptr->fval | (c_ptr->lr << 4) | (c_ptr->fm << 5) |
(c_ptr->pl << 6) | (c_ptr->tl << 7);
if (char_tmp != prev_char || count == MAX_UCHAR) {
wr_byte((int8u) count);
wr_byte(prev_char);
prev_char = char_tmp;
count = 1;
} else
count++;
}
/* save last entry */
wr_byte((int8u) count);
wr_byte(prev_char);
#ifdef MSDOS
/* must change graphics symbols for walls and floors back to default chars,
* this is necessary so that if the user changes the graphics line, the
* program will be able change all existing walls/floors to the new symbol
*/
t_ptr = &t_list[tcptr - 1];
for (i = tcptr - 1; i >= MIN_TRIX; i--) {
if (t_ptr->tchar == wallsym)
t_ptr->tchar = '#';
t_ptr--;
}
#endif
wr_short((int16u) tcptr);
for (i = MIN_TRIX; i < tcptr; i++)
wr_item(&t_list[i]);
wr_short((int16u) mfptr);
for (i = MIN_MONIX; i < mfptr; i++)
wr_monster(&m_list[i]);
/* Save ghost names & stats etc... */
if (!c_list[MAX_CREATURES - 1].name) {
/* Can't dereference NULL! */
c_list[MAX_CREATURES - 1].name = (char*)malloc(101);
bzero((char *)c_list[MAX_CREATURES - 1].name, 101);
}
wr_bytes(c_list[MAX_CREATURES - 1].name, 100);
wr_long((int32u) c_list[MAX_CREATURES - 1].cmove);
wr_long((int32u) c_list[MAX_CREATURES - 1].spells);
wr_long((int32u) c_list[MAX_CREATURES - 1].cdefense);
{
int16u temp;
/* fix player ghost's exp bug. The mexp field is really an int32u, but the
* savefile was writing/reading an int16u. Since I don't want to change
* the savefile format, this insures that the low bits of mexp are written (No
* ghost should be worth more than 64K (Melkor is only worth 60k!), but we
* check anyway). Using temp insures that the low bits are all written, and works
* perfectly with a similar fix when* loading a character. -CFT
*/
if (c_list[MAX_CREATURES - 1].mexp > (int32u) 0xff00)
temp = (int16u) 0xff00;
else
temp = (int16u) c_list[MAX_CREATURES - 1].mexp;
wr_short((int16u) temp);
}
wr_short((int8u) c_list[MAX_CREATURES - 1].sleep);
wr_byte((int8u) c_list[MAX_CREATURES - 1].aaf);
wr_short((int8u) c_list[MAX_CREATURES - 1].ac);
wr_byte((int8u) c_list[MAX_CREATURES - 1].speed);
wr_byte((int8u) c_list[MAX_CREATURES - 1].cchar);
wr_bytes(c_list[MAX_CREATURES - 1].hd, 2);
wr_bytes(c_list[MAX_CREATURES - 1].damage, sizeof(attid) * 4);
wr_short((int16u) c_list[MAX_CREATURES - 1].level);
if (ferror(fileptr) || (fflush(fileptr) == EOF))
return FALSE;
return TRUE;
}
int
save_char()
{
vtype temp;
char *tmp2;
#ifdef SECURE
beGames();
#endif
if (death && NO_SAVE)
return TRUE;
if (_save_char(savefile)) {
tmp2 = basename(savefile);
(void)sprintf(temp, "%s/p.%s", ANGBAND_SAV, (tmp2 + 1));
unlink(temp);
} else {
return FALSE;
}
#ifdef SECURE
bePlayer();
#endif
return TRUE;
}
int
_save_char(fnam)
char *fnam;
{
vtype temp;
int ok, fd;
int8u char_tmp;
if (log_index < 0)
return TRUE; /* Nothing to save. */
nosignals();
put_qio();
disturb(1, 0); /* Turn off resting and searching. */
change_speed(-pack_heavy); /* Fix the speed */
pack_heavy = 0;
ok = FALSE;
#ifndef ATARIST_MWC
fd = (-1);
fileptr = NULL; /* Do not assume it has been init'ed */
#ifdef SET_UID
fd = my_topen(fnam, O_RDWR | O_CREAT | O_EXCL, 0600);
#else
fd = my_topen(fnam, O_RDWR | O_CREAT | O_EXCL, 0666);
#endif
if (fd < 0 && access(fnam, 0) >= 0 &&
(from_savefile ||
(wizard && get_check("Can't make new savefile. Overwrite old?")))) {
#ifdef SET_UID
(void)chmod(fnam, 0600);
fd = my_topen(fnam, O_RDWR | O_TRUNC, 0600);
#else
(void)chmod(fnam, 0666);
fd = my_topen(fnam, O_RDWR | O_TRUNC, 0666);
#endif
}
if (fd >= 0) {
(void)close(fd);
#endif /* !ATARIST_MWC */
/* GCC for atari st defines atarist */
#if defined(atarist) || defined(ATARIST_MWC) || defined(MSDOS) || defined(__MINT__)
fileptr = my_tfopen(savefile, "wb");
#else
fileptr = my_tfopen(savefile, "w");
#endif
#ifndef ATARIST_MWC
}
#endif
if (fileptr != NULL) {
#ifdef MSDOS
(void)setmode(fileno(fileptr), O_BINARY);
#endif
xor_byte = 0;
wr_byte((int8u) CUR_VERSION_MAJ);
xor_byte = 0;
wr_byte((int8u) CUR_VERSION_MIN);
xor_byte = 0;
wr_byte((int8u) PATCH_LEVEL);
xor_byte = 0;
char_tmp = randint(256) - 1;
wr_byte(char_tmp);
/* Note that xor_byte is now equal to char_tmp */
ok = sv_write();
if (fclose(fileptr) == EOF)
ok = FALSE;
}
if (!ok) {
if (fd >= 0)
(void)unlink(fnam);
signals();
if (fd >= 0)
(void)sprintf(temp, "Error writing to savefile");
else
/* here? */
(void)sprintf(temp, "Can't create new savefile");
msg_print(temp);
return FALSE;
} else
character_saved = 1;
turn = (-1);
log_index = (-1);
signals();
return TRUE;
}
/* Certain checks are ommitted for the wizard. -CJS- */
int
get_char(generate)
int *generate;
{
int i, j, fd, c, ok, total_count;
int32u l, age, time_saved;
vtype temp;
int16u int16u_tmp;
register cave_type *c_ptr;
register recall_type *r_ptr;
struct misc *m_ptr;
struct stats *s_ptr;
register struct flags *f_ptr;
store_type *st_ptr;
int8u char_tmp, ychar, xchar, count;
free_turn_flag = TRUE; /* So a feeling isn't generated upon reloading -DGK */
nosignals();
*generate = TRUE;
fd = (-1);
if (access(savefile, 0) < 0) {
signals();
msg_print("Savefile does not exist.");
return FALSE;
}
clear_screen();
(void)sprintf(temp, "Restoring Character.");
put_buffer(temp, 23, 0);
sleep(1);
if (turn >= 0)
msg_print("IMPOSSIBLE! Attempt to restore while still alive!");
/* Allow restoring a file belonging to someone else - if we can delete it. */
/* Hence first try to read without doing a chmod. */
else if ((fd = my_topen(savefile, O_RDONLY, 0)) < 0)
msg_print("Can't open file for reading.");
else {
#ifndef SET_UID
struct stat statbuf;
#endif
turn = (-1);
log_index = (-1);
ok = TRUE;
#ifndef SET_UID
(void)fstat(fd, &statbuf);
#endif
(void)close(fd);
/* GCC for atari st defines atarist */
#if defined(__MINT__) || defined(atarist) || defined(ATARIST_MWC) || defined(MSDOS)
fileptr = my_tfopen(savefile, "rb");
#else
fileptr = my_tfopen(savefile, "r");
#endif
if (fileptr == NULL)
goto error;
prt("Restoring Memory...", 0, 0);
put_qio();
xor_byte = 0;
rd_byte(&version_maj);
xor_byte = 0;
rd_byte(&version_min);
xor_byte = 0;
rd_byte(&patch_level);
xor_byte = 0;
rd_byte(&xor_byte);
/* This boneheadedness is a direct result of the fact that Angband 2.4
* had version constants of 5.2, not 2.4. 2.5 inherited this. 2.6 fixes
* the problem. Note that there must never be a 5.2.x version of Angband,
* or else this code will get confused. -CWS
*/
if ((version_maj == 5) && (version_min == 2)) {
version_maj = 2;
version_min = 5;
}
if ((version_maj != CUR_VERSION_MAJ)
|| (version_min > CUR_VERSION_MIN)
|| (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)) {
prt("Sorry. This savefile is from a different version of Angband.",
2, 0);
goto error;
}
put_qio();
rd_long(&GROND);
rd_long(&RINGIL);
rd_long(&AEGLOS);
rd_long(&ARUNRUTH);
rd_long(&MORMEGIL);
rd_long(&ANGRIST);
rd_long(&GURTHANG);
rd_long(&CALRIS);
rd_long(&ANDURIL);
rd_long(&STING);
rd_long(&ORCRIST);
rd_long(&GLAMDRING);
rd_long(&DURIN);
rd_long(&AULE);
rd_long(&THUNDERFIST);
rd_long(&BLOODSPIKE);
rd_long(&DOOMCALLER);
rd_long(&NARTHANC);
rd_long(&NIMTHANC);
rd_long(&DETHANC);
rd_long(&GILETTAR);
rd_long(&RILIA);
rd_long(&BELANGIL);
rd_long(&BALLI);
rd_long(&LOTHARANG);
rd_long(&FIRESTAR);
rd_long(&ERIRIL);
rd_long(&CUBRAGOL);
rd_long(&BARD);
rd_long(&COLLUIN);
rd_long(&HOLCOLLETH);
rd_long(&TOTILA);
rd_long(&PAIN);
rd_long(&ELVAGIL);
rd_long(&AGLARANG);
rd_long(&EORLINGAS);
rd_long(&BARUKKHELED);
rd_long(&WRATH);
rd_long(&HARADEKKET);
rd_long(&MUNDWINE);
rd_long(&GONDRICAM);
rd_long(&ZARCUTHRA);
rd_long(&CARETH);
rd_long(&FORASGIL);
rd_long(&CRISDURIAN);
rd_long(&COLANNON);
rd_long(&HITHLOMIR);
rd_long(&THALKETTOTH);
rd_long(&ARVEDUI);
rd_long(&THRANDUIL);
rd_long(&THENGEL);
rd_long(&HAMMERHAND);
rd_long(&CELEGORM);
rd_long(&THROR);
rd_long(&MAEDHROS);
rd_long(&OLORIN);
rd_long(&ANGUIREL);
rd_long(&OROME);
rd_long(&EONWE);
rd_long(&THEODEN);
rd_long(&ULMO);
rd_long(&OSONDIR);
rd_long(&TURMIL);
rd_long(&CASPANION);
rd_long(&TIL);
rd_long(&DEATHWREAKER);
rd_long(&AVAVIR);
rd_long(&TARATOL);
if (to_be_wizard)
prt("Loaded Weapon Artifacts", 2, 0);
put_qio();
rd_long(&DOR_LOMIN);
rd_long(&NENYA);
rd_long(&NARYA);
rd_long(&VILYA);
rd_long(&BELEGENNON);
rd_long(&FEANOR);
rd_long(&ISILDUR);
rd_long(&SOULKEEPER);
rd_long(&FINGOLFIN);
rd_long(&ANARION);
rd_long(&POWER);
rd_long(&PHIAL);
rd_long(&BELEG);
rd_long(&DAL);
rd_long(&PAURHACH);
rd_long(&PAURNIMMEN);
rd_long(&PAURAEGEN);
rd_long(&PAURNEN);
rd_long(&CAMMITHRIM);
rd_long(&CAMBELEG);
rd_long(&INGWE);
rd_long(&CARLAMMAS);
rd_long(&HOLHENNETH);
rd_long(&AEGLIN);
rd_long(&CAMLOST);
rd_long(&NIMLOTH);
rd_long(&NAR);
rd_long(&BERUTHIEL);
rd_long(&GORLIM);
rd_long(&ELENDIL);
rd_long(&THORIN);
rd_long(&CELEBORN);
rd_long(&THRAIN);
rd_long(&GONDOR);
rd_long(&THINGOL);
rd_long(&THORONGIL);
rd_long(&LUTHIEN);
rd_long(&TUOR);
rd_long(&ROHAN);
rd_long(&TULKAS);
rd_long(&NECKLACE);
rd_long(&BARAHIR);
rd_long(&RAZORBACK);
rd_long(&BLADETURNER);
if (to_be_wizard)
prt("Loaded Armour Artifacts", 3, 0);
put_qio();
for (i = 0; i < MAX_QUESTS; i++)
rd_long(&quests[i]);
if (to_be_wizard)
prt("Loaded Quests", 4, 0);
for (i = 0; i < MAX_CREATURES; i++)
rd_unique(&u_list[i]);
if (to_be_wizard)
prt("Loaded Unique Beasts", 5, 0);
put_qio();
rd_short(&int16u_tmp);
while (int16u_tmp != 0xFFFF) {
if (int16u_tmp >= MAX_CREATURES)
goto error;
r_ptr = &c_recall[int16u_tmp];
rd_long(&r_ptr->r_cmove);
rd_long(&r_ptr->r_spells);
rd_long(&r_ptr->r_spells2);
rd_long(&r_ptr->r_spells3);
rd_short(&r_ptr->r_kills);
rd_short(&r_ptr->r_deaths);
rd_long(&r_ptr->r_cdefense);
rd_byte(&r_ptr->r_wake);
rd_byte(&r_ptr->r_ignore);
rd_bytes(r_ptr->r_attacks, MAX_MON_NATTACK);
rd_short(&int16u_tmp);
}
if (to_be_wizard)
prt("Loaded Recall Memory", 6, 0);
put_qio();
rd_short((int16u *) & log_index);
rd_long(&l);
if ((version_maj >= 2) && (version_min >= 6)) {
rd_long(&l);
rd_long(&l);
rd_long(&l);
}
if (to_be_wizard)
prt("Loaded Options Memory", 7, 0);
put_qio();
if (l & 1)
find_cut = TRUE;
else
find_cut = FALSE;
if (l & 2)
find_examine = TRUE;
else
find_examine = FALSE;
if (l & 4)
find_prself = TRUE;
else
find_prself = FALSE;
if (l & 8)
find_bound = TRUE;
else
find_bound = FALSE;
if (l & 16)
prompt_carry_flag = TRUE;
else
prompt_carry_flag = FALSE;
if (l & 32)
rogue_like_commands = TRUE;
else
rogue_like_commands = FALSE;
if (l & 64)
show_weight_flag = TRUE;
else
show_weight_flag = FALSE;
if (l & 128)
highlight_seams = TRUE;
else
highlight_seams = FALSE;
if (l & 0x100L)
find_ignore_doors = TRUE;
else
find_ignore_doors = FALSE;
if (l & 0x200L)
no_haggle_flag = TRUE;
else
no_haggle_flag = FALSE;
if (l & 0x400L)
carry_query_flag = FALSE;
else
carry_query_flag = TRUE;
if (l & 0x1000L)
unfelt = TRUE;
else
unfelt = FALSE;
delay_spd = ((l >> 13) & 0xf);
if (delay_spd > 10)
delay_spd = 10; /* bounds check for delay_speed -CWS */
if (delay_spd < 0)
delay_spd = 0;
hitpoint_warn = ((l >> 17) & 0xf);
if (l & 0x00400000L) /* don't do "black Mushroom of Curing" */
plain_descriptions = TRUE;
else
plain_descriptions = FALSE;
if (l & 0x00800000L)
show_equip_weight_flag = TRUE;
else
show_equip_weight_flag = FALSE;
feeling = ((l >> 24) & 0xf);
if (feeling > 10)
feeling = 0; /* bounds for level feelings -CWS */
if (feeling < 0)
feeling = 0;
if (l & 0x20000000L)
equippy_chars = TRUE; /* equippy chars option -CWS */
else
equippy_chars = FALSE;
if (l & 0x40000000L)
quick_messages = TRUE; /* quick messages option -CWS */
else
quick_messages = FALSE;
if (to_be_wizard && (l & 0x80000000L)
&& get_check("Resurrect a dead character?"))
l &= ~0x80000000L;
if ((l & 0x80000000L) == 0) {
m_ptr = &py.misc;
rd_string(m_ptr->name);
rd_byte(&m_ptr->male);
rd_long((int32u *) & m_ptr->au);
rd_long((int32u *) & m_ptr->max_exp);
rd_long((int32u *) & m_ptr->exp);
rd_short(&m_ptr->exp_frac);
rd_short(&m_ptr->age);
rd_short(&m_ptr->ht);
rd_short(&m_ptr->wt);
rd_short(&m_ptr->lev);
rd_short(&m_ptr->max_dlv);
rd_short((int16u *) & m_ptr->srh);
rd_short((int16u *) & m_ptr->fos);
rd_short((int16u *) & m_ptr->bth);
rd_short((int16u *) & m_ptr->bthb);
rd_short((int16u *) & m_ptr->mana);
rd_short((int16u *) & m_ptr->mhp);
rd_short((int16u *) & m_ptr->ptohit);
rd_short((int16u *) & m_ptr->ptodam);
rd_short((int16u *) & m_ptr->pac);
rd_short((int16u *) & m_ptr->ptoac);
rd_short((int16u *) & m_ptr->dis_th);
rd_short((int16u *) & m_ptr->dis_td);
rd_short((int16u *) & m_ptr->dis_ac);
rd_short((int16u *) & m_ptr->dis_tac);
rd_short((int16u *) & m_ptr->disarm);
rd_short((int16u *) & m_ptr->save);
rd_short((int16u *) & m_ptr->sc);
rd_short((int16u *) & m_ptr->stl);
rd_byte(&m_ptr->pclass);
rd_byte(&m_ptr->prace);
rd_byte(&m_ptr->hitdie);
rd_byte(&m_ptr->expfact);
rd_short((int16u *) & m_ptr->cmana);
rd_short(&m_ptr->cmana_frac);
rd_short((int16u *) & m_ptr->chp);
rd_short(&m_ptr->chp_frac);
for (i = 0; i < 4; i++)
rd_string(m_ptr->history[i]);
s_ptr = &py.stats;
rd_shorts(s_ptr->max_stat, 6);
if (version_maj <= 2 && version_min <=5 && patch_level <= 6)
rd_shorts(s_ptr->cur_stat, 6);
else
rd_bytes(s_ptr->cur_stat, 6); /* -TL */
rd_shorts((int16u *) s_ptr->mod_stat, 6);
rd_shorts(s_ptr->use_stat, 6);
f_ptr = &py.flags;
rd_long(&f_ptr->status);
rd_short((int16u *) & f_ptr->rest);
rd_short((int16u *) & f_ptr->blind);
rd_short((int16u *) & f_ptr->paralysis);
rd_short((int16u *) & f_ptr->confused);
rd_short((int16u *) & f_ptr->food);
rd_short((int16u *) & f_ptr->food_digested);
rd_short((int16u *) & f_ptr->protection);
rd_short((int16u *) & f_ptr->speed);
rd_short((int16u *) & f_ptr->fast);
rd_short((int16u *) & f_ptr->slow);
rd_short((int16u *) & f_ptr->afraid);
rd_short((int16u *) & f_ptr->cut);
rd_short((int16u *) & f_ptr->stun);
rd_short((int16u *) & f_ptr->poisoned);
rd_short((int16u *) & f_ptr->image);
rd_short((int16u *) & f_ptr->protevil);
rd_short((int16u *) & f_ptr->invuln);
rd_short((int16u *) & f_ptr->hero);
rd_short((int16u *) & f_ptr->shero);
rd_short((int16u *) & f_ptr->shield);
rd_short((int16u *) & f_ptr->blessed);
rd_short((int16u *) & f_ptr->resist_heat);
rd_short((int16u *) & f_ptr->resist_cold);
rd_short((int16u *) & f_ptr->resist_acid);
rd_short((int16u *) & f_ptr->resist_light);
rd_short((int16u *) & f_ptr->resist_poison);
rd_short((int16u *) & f_ptr->detect_inv);
rd_short((int16u *) & f_ptr->word_recall);
rd_short((int16u *) & f_ptr->see_infra);
rd_short((int16u *) & f_ptr->tim_infra);
rd_byte(&f_ptr->see_inv);
rd_byte(&f_ptr->teleport);
rd_byte(&f_ptr->free_act);
rd_byte(&f_ptr->slow_digest);
rd_byte(&f_ptr->aggravate);
rd_byte(&f_ptr->fire_resist);
rd_byte(&f_ptr->cold_resist);
rd_byte(&f_ptr->acid_resist);
rd_byte(&f_ptr->regenerate);
rd_byte(&f_ptr->lght_resist);
rd_byte(&f_ptr->ffall);
rd_byte(&f_ptr->sustain_str);
rd_byte(&f_ptr->sustain_int);
rd_byte(&f_ptr->sustain_wis);
rd_byte(&f_ptr->sustain_con);
rd_byte(&f_ptr->sustain_dex);
rd_byte(&f_ptr->sustain_chr);
rd_byte(&f_ptr->confuse_monster);
rd_byte(&f_ptr->new_spells);
rd_byte(&f_ptr->poison_resist);
rd_byte(&f_ptr->hold_life);
rd_byte(&f_ptr->telepathy);
rd_byte(&f_ptr->fire_im);
rd_byte(&f_ptr->acid_im);
rd_byte(&f_ptr->poison_im);
rd_byte(&f_ptr->cold_im);
rd_byte(&f_ptr->light_im);
rd_byte(&f_ptr->light);
rd_byte(&f_ptr->confusion_resist);
rd_byte(&f_ptr->sound_resist);
rd_byte(&f_ptr->light_resist);
rd_byte(&f_ptr->dark_resist);
rd_byte(&f_ptr->chaos_resist);
rd_byte(&f_ptr->disenchant_resist);
rd_byte(&f_ptr->shards_resist);
rd_byte(&f_ptr->nexus_resist);
rd_byte(&f_ptr->blindness_resist);
rd_byte(&f_ptr->nether_resist);
if ((version_maj >= 2) && (version_min >= 6))
rd_byte(&f_ptr->fear_resist);
else
f_ptr->fear_resist = 0; /* sigh */
rd_short((int16u *) & missile_ctr);
rd_long((int32u *) & turn);
if ((version_maj >= 2) && (version_min >= 6))
rd_long((int32u *) & old_turn);
else
old_turn = turn; /* best we can do... -CWS */
rd_short((int16u *) & inven_ctr);
if (inven_ctr > INVEN_WIELD) {
prt("ERROR in inven_ctr", 8, 0);
goto error;
}
for (i = 0; i < inven_ctr; i++)
rd_item(&inventory[i]);
for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++)
rd_item(&inventory[i]);
rd_short((int16u *) & inven_weight);
rd_short((int16u *) & equip_ctr);
rd_long(&spell_learned);
rd_long(&spell_worked);
rd_long(&spell_forgotten);
rd_long(&spell_learned2);
rd_long(&spell_worked2);
rd_long(&spell_forgotten2);
rd_bytes(spell_order, 64);
rd_bytes(object_ident, OBJECT_IDENT_SIZE);
rd_long(&randes_seed);
rd_long(&town_seed);
rd_short((int16u *) & last_msg);
for (i = 0; i < MAX_SAVE_MSG; i++)
rd_string(old_msg[i]);
rd_short((int16u *) & panic_save);
rd_short((int16u *) & total_winner);
rd_short((int16u *) & noscore);
rd_shorts(player_hp, MAX_PLAYER_LEVEL);
for (i = 0; i < MAX_STORES; i++) {
st_ptr = &store[i];
rd_long((int32u *) & st_ptr->store_open);
rd_short((int16u *) & st_ptr->insult_cur);
rd_byte(&st_ptr->owner);
rd_byte(&st_ptr->store_ctr);
rd_short(&st_ptr->good_buy);
rd_short(&st_ptr->bad_buy);
if (st_ptr->store_ctr > STORE_INVEN_MAX) {
prt("ERROR in store_ctr", 9, 0);
goto error;
}
for (j = 0; j < st_ptr->store_ctr; j++) {
rd_long((int32u *) & st_ptr->store_inven[j].scost);
rd_item(&st_ptr->store_inven[j].sitem);
}
}
rd_long(&time_saved);
#ifndef SET_UID
#ifndef ALLOW_FIDDLING
if (!to_be_wizard) {
if (time_saved > (statbuf.st_ctime + 100) ||
time_saved < (statbuf.st_ctime - 100)) {
prt("Fiddled save file", 10, 0);
goto error;
}
}
#endif
#endif
rd_string(died_from);
}
if ((c = getc(fileptr)) == EOF || (l & 0x80000000L)) {
if ((l & 0x80000000L) == 0) {
if (!to_be_wizard || turn < 0) {
prt("ERROR in to_be_wizard", 10, 0);
goto error;
}
prt("Attempting a resurrection!", 0, 0);
if (py.misc.chp < 0) {
py.misc.chp = 0;
py.misc.chp_frac = 0;
}
/* don't let him starve to death immediately */
if (py.flags.food < 5000)
py.flags.food = 5000;
cure_poison();
cure_blindness();
cure_confusion();
remove_fear();
if (py.flags.image > 0)
py.flags.image = 0;
if (py.flags.cut > 0)
py.flags.cut = 0;
if (py.flags.stun > 0) {
if (py.flags.stun > 50) {
py.misc.ptohit += 20;
py.misc.ptodam += 20;
} else {
py.misc.ptohit += 5;
py.misc.ptodam += 5;
}
py.flags.stun = 0;
}
if (py.flags.word_recall > 0)
py.flags.word_recall = 0;
dun_level = 0; /* Resurrect on the town level. */
character_generated = 1;
/* set noscore to indicate a resurrection, and don't enter wizard mode */
to_be_wizard = FALSE;
noscore |= 0x1;
} else {
prt("Restoring Memory of a departed spirit...", 0, 0);
turn = (-1);
old_turn = (-1);
}
put_qio();
/* The log_index of the previous incarnation is here if later version
* want to use it. For now, throw it away and get a new log.
*/
log_index = (-1);
goto closefiles;
}
if (ungetc(c, fileptr) == EOF) {
prt("ERROR in ungetc", 11, 0);
goto error;
}
prt("Restoring Character...", 0, 0);
put_qio();
/* only level specific info should follow, not present for dead characters */
rd_short((int16u *) & dun_level);
rd_short((int16u *) & char_row);
rd_short((int16u *) & char_col);
rd_short((int16u *) & mon_tot_mult);
rd_short((int16u *) & cur_height);
rd_short((int16u *) & cur_width);
rd_short((int16u *) & max_panel_rows);
rd_short((int16u *) & max_panel_cols);
/* read in the creature ptr info */
rd_byte(&char_tmp);
while (char_tmp != 0xFF) {
ychar = char_tmp;
rd_byte(&xchar);
/* let's correctly fix the invisible monster bug -CWS */
if ((version_maj >= 2) && (version_min >= 6)) {
rd_short((int16u *) & int16u_tmp);
cave[ychar][xchar].cptr = int16u_tmp;
} else {
rd_byte((int8u *) & char_tmp);
cave[ychar][xchar].cptr = char_tmp;
}
if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT) {
vtype t1;
sprintf(t1,
"Error in creature ptr info: x=%x, y=%x, char_tmp=%x",
(unsigned) xchar, (unsigned) ychar, (unsigned) char_tmp);
prt(t1, 11, 0);
}
rd_byte(&char_tmp);
}
/* read in the treasure ptr info */
rd_byte(&char_tmp);
while (char_tmp != 0xFF) {
ychar = char_tmp;
rd_byte(&xchar);
rd_short((int16u *) & int16u_tmp);
if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT) {
prt("Error in treasure pointer info", 12, 0);
goto error;
}
cave[ychar][xchar].tptr = int16u_tmp;
rd_byte(&char_tmp);
}
/* read in the rest of the cave info */
c_ptr = &cave[0][0];
total_count = 0;
while (total_count != MAX_HEIGHT * MAX_WIDTH) {
rd_byte(&count);
rd_byte(&char_tmp);
for (i = count; i > 0; i--) {
#ifndef ATARIST_MWC
if (c_ptr >= &cave[MAX_HEIGHT][0]) {
prt("ERROR in cave size", 13, 0);
goto error;
}
#endif
c_ptr->fval = char_tmp & 0xF;
c_ptr->lr = (char_tmp >> 4) & 0x1;
c_ptr->fm = (char_tmp >> 5) & 0x1;
c_ptr->pl = (char_tmp >> 6) & 0x1;
c_ptr->tl = (char_tmp >> 7) & 0x1;
c_ptr++;
}
total_count += count;
}
rd_short((int16u *) & tcptr);
if (tcptr > MAX_TALLOC) {
prt("ERROR in MAX_TALLOC", 14, 0);
goto error;
}
for (i = MIN_TRIX; i < tcptr; i++)
rd_item(&t_list[i]);
rd_short((int16u *) & mfptr);
if (mfptr > MAX_MALLOC) {
prt("ERROR in MAX_MALLOC", 15, 0);
goto error;
}
for (i = MIN_MONIX; i < mfptr; i++) {
rd_monster(&m_list[i]);
}
#ifdef MSDOS
/* change walls and floors to graphic symbols */
t_ptr = &t_list[tcptr - 1];
for (i = tcptr - 1; i >= MIN_TRIX; i--) {
if (t_ptr->tchar == '#')
t_ptr->tchar = wallsym;
t_ptr--;
}
#endif
/* Restore ghost names & stats etc... */
/* Allocate storage for name */
c_list[MAX_CREATURES - 1].name = (char*)malloc(101);
bzero((char *)c_list[MAX_CREATURES - 1].name, 101);
*((char *) c_list[MAX_CREATURES - 1].name) = 'A';
rd_bytes((int8u *) (c_list[MAX_CREATURES - 1].name), 100);
rd_long((int32u *) & (c_list[MAX_CREATURES - 1].cmove));
rd_long((int32u *) & (c_list[MAX_CREATURES - 1].spells));
rd_long((int32u *) & (c_list[MAX_CREATURES - 1].cdefense));
{
int16u t1;
/* fix player ghost's exp bug. The mexp field is really an int32u, but the
* savefile was writing/ reading an int16u. Since I don't want to change
* the savefile format, this insures that the mexp field is loaded, and that
* the "high bits" of mexp do not contain garbage values which could mean that
* player ghost are worth millions of exp. -CFT
*/
rd_short((int16u *) & t1);
c_list[MAX_CREATURES - 1].mexp = (int32u) t1;
}
/* more stupid size bugs that would've never been needed if these variables
* had been given enough space in the first place -CWS
*/
if ((version_maj >= 2) && (version_min >= 6))
rd_short((int16u *) & (c_list[MAX_CREATURES - 1].sleep));
else
rd_byte((int8u *) & (c_list[MAX_CREATURES - 1].sleep));
rd_byte((int8u *) & (c_list[MAX_CREATURES - 1].aaf));
if ((version_maj >= 2) && (version_min >= 6))
rd_short((int16u *) & (c_list[MAX_CREATURES - 1].ac));
else
rd_byte((int8u *) & (c_list[MAX_CREATURES - 1].ac));
rd_byte((int8u *) & (c_list[MAX_CREATURES - 1].speed));
rd_byte((int8u *) & (c_list[MAX_CREATURES - 1].cchar));
rd_bytes((int8u *) (c_list[MAX_CREATURES - 1].hd), 2);
rd_bytes((int8u *) (c_list[MAX_CREATURES - 1].damage), sizeof(attid) * 4);
rd_short((int16u *) & (c_list[MAX_CREATURES - 1].level));
*generate = FALSE; /* We have restored a cave - no need to generate. */
if ((version_min == 1 && patch_level < 3)
|| (version_min == 0))
for (i = 0; i < MAX_STORES; i++) {
st_ptr = &store[i];
rd_long((int32u *) & st_ptr->store_open);
rd_short((int16u *) & st_ptr->insult_cur);
rd_byte(&st_ptr->owner);
rd_byte(&st_ptr->store_ctr);
rd_short(&st_ptr->good_buy);
rd_short(&st_ptr->bad_buy);
if (st_ptr->store_ctr > STORE_INVEN_MAX) {
prt("ERROR in STORE_INVEN_MAX", 16, 0);
goto error;
}
for (j = 0; j < st_ptr->store_ctr; j++) {
rd_long((int32u *) & st_ptr->store_inven[j].scost);
rd_item(&st_ptr->store_inven[j].sitem);
}
}
/* read the time that the file was saved */
rd_long(&time_saved);
if (ferror(fileptr)) {
prt("FILE ERROR", 17, 0);
goto error;
}
if (turn < 0) {
prt("Error = turn < 0", 7, 0);
error:
ok = FALSE; /* Assume bad data. */
} else {
/* don't overwrite the killed by string if character is dead */
if (py.misc.chp >= 0)
(void)strcpy(died_from, "(alive and well)");
character_generated = 1;
}
closefiles:
if (fileptr != NULL) {
if (fclose(fileptr) < 0)
ok = FALSE;
}
if (fd >= 0)
(void)close(fd);
if (!ok)
msg_print("Error during reading of file.");
else if (turn >= 0 && !_new_log())
msg_print("Can't log player in the log file.");
else {
/* let the user overwrite the old savefile when save/quit */
from_savefile = 1;
signals();
if (turn >= 0) { /* Only if a full restoration. */
weapon_heavy = FALSE;
pack_heavy = 0;
check_strength();
/* rotate store inventory, depending on how old the save file */
/* is foreach day old (rounded up), call store_maint */
/* calculate age in seconds */
start_time = time((long *)0);
/* check for reasonable values of time here ... */
if (start_time < time_saved)
age = 0;
else
age = start_time - time_saved;
age = (age + 43200L) / 86400L; /* age in days */
if (age > 10)
age = 10; /* in case savefile is very old */
for (i = 0; i < age; i++)
store_maint();
}
/* if (noscore) msg_print("This save file cannot be used to get on the score board."); */
if (version_maj != CUR_VERSION_MAJ
|| version_min != CUR_VERSION_MIN) {
(void)sprintf(temp,
"Save file version %d.%d %s on game version %d.%d.",
version_maj, version_min,
version_maj == CUR_VERSION_MAJ
? "accepted" : "very risky",
CUR_VERSION_MAJ, CUR_VERSION_MIN);
msg_print(temp);
}
if (turn >= 0) {
char *tmp2;
tmp2 = basename(savefile);
(void)sprintf(temp, "%s/p.%s", ANGBAND_SAV, (tmp2 + 1));
link(savefile, temp);
unlink(savefile);
return TRUE;
} else {
return FALSE; /* Only restored options and monster memory. */
}
}
}
turn = (-1);
log_index = (-1);
prt("Please try again without that savefile.", 1, 0);
signals();
#ifdef MAC
*exit_flag = TRUE;
#else
exit_game();
#endif
return FALSE; /* not reached, unless on mac */
}
static void
wr_byte(c)
int8u c;
{
xor_byte ^= c;
(void)putc((int)xor_byte, fileptr);
}
static void
wr_short(s)
int16u s;
{
xor_byte ^= (s & 0xFF);
(void)putc((int)xor_byte, fileptr);
xor_byte ^= ((s >> 8) & 0xFF);
(void)putc((int)xor_byte, fileptr);
}
static void
wr_long(l)
register int32u l;
{
xor_byte ^= (l & 0xFF);
(void)putc((int)xor_byte, fileptr);
xor_byte ^= ((l >> 8) & 0xFF);
(void)putc((int)xor_byte, fileptr);
xor_byte ^= ((l >> 16) & 0xFF);
(void)putc((int)xor_byte, fileptr);
xor_byte ^= ((l >> 24) & 0xFF);
(void)putc((int)xor_byte, fileptr);
}
static void
wr_bytes(c, count)
int8u *c;
register int count;
{
register int i;
register int8u *ptr;
ptr = c;
for (i = 0; i < count; i++) {
xor_byte ^= *ptr++;
(void)putc((int)xor_byte, fileptr);
}
}
static void
wr_string(str)
register char *str;
{
while (*str != '\0') {
xor_byte ^= *str++;
(void)putc((int)xor_byte, fileptr);
}
xor_byte ^= *str;
(void)putc((int)xor_byte, fileptr);
}
static void
wr_shorts(s, count)
int16u *s;
register int count;
{
register int i;
register int16u *sptr;
sptr = s;
for (i = 0; i < count; i++) {
xor_byte ^= (*sptr & 0xFF);
(void)putc((int)xor_byte, fileptr);
xor_byte ^= ((*sptr++ >> 8) & 0xFF);
(void)putc((int)xor_byte, fileptr);
}
}
static void
wr_item(item)
register inven_type *item;
{
wr_short(item->index);
wr_byte(item->name2);
wr_string(item->inscrip);
wr_long(item->flags);
wr_byte(item->tval);
wr_byte(item->tchar);
wr_short((int16u) item->p1);
wr_long((int32u) item->cost);
wr_byte(item->subval);
wr_byte(item->number);
wr_short(item->weight);
wr_short((int16u) item->tohit);
wr_short((int16u) item->todam);
wr_short((int16u) item->ac);
wr_short((int16u) item->toac);
wr_bytes(item->damage, 2);
wr_byte(item->level);
wr_byte(item->ident);
wr_long(item->flags2);
wr_short((int16u) item->timeout);
}
static void
wr_monster(mon)
register monster_type *mon;
{
wr_short((int16u) mon->hp);
wr_short((int16u) mon->maxhp); /* added -CWS */
wr_short((int16u) mon->csleep);
wr_short((int16u) mon->cspeed);
wr_short(mon->mptr);
wr_byte(mon->fy);
wr_byte(mon->fx);
wr_byte(mon->cdis);
wr_byte(mon->ml);
wr_byte(mon->stunned);
wr_byte(mon->confused);
wr_byte(mon->monfear); /* added -CWS */
}
static void
rd_byte(ptr)
int8u *ptr;
{
int8u c;
c = getc(fileptr) & 0xFF;
*ptr = c ^ xor_byte;
xor_byte = c;
}
static void
rd_short(ptr)
int16u *ptr;
{
int8u c;
int16u s;
c = (getc(fileptr) & 0xFF);
s = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
s |= (int16u) (c ^ xor_byte) << 8;
*ptr = s;
}
static void
rd_long(ptr)
int32u *ptr;
{
register int32u l;
register int8u c;
c = (getc(fileptr) & 0xFF);
l = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
l |= (int32u) (c ^ xor_byte) << 8;
c = (getc(fileptr) & 0xFF);
l |= (int32u) (c ^ xor_byte) << 16;
xor_byte = (getc(fileptr) & 0xFF);
l |= (int32u) (c ^ xor_byte) << 24;
*ptr = l;
}
static void
rd_bytes(ptr, count)
int8u *ptr;
int count;
{
int i;
int8u c, nc;
for (i = 0; i < count; i++) {
c = (getc(fileptr) & 0xFF);
nc = c ^ xor_byte;
*ptr = nc;
ptr++;
xor_byte = c;
}
}
static void
rd_string(str)
char *str;
{
register int8u c;
do {
c = (getc(fileptr) & 0xFF);
*str = c ^ xor_byte;
xor_byte = c;
}
while (*str++ != '\0');
}
static void
rd_shorts(ptr, count)
int16u *ptr;
register int count;
{
register int i;
register int16u *sptr;
register int16u s;
int8u c;
sptr = ptr;
for (i = 0; i < count; i++) {
c = (getc(fileptr) & 0xFF);
s = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
s |= (int16u) (c ^ xor_byte) << 8;
*sptr++ = s;
}
}
static void
rd_item(item)
register inven_type *item;
{
rd_short(&item->index);
rd_byte(&item->name2);
rd_string(item->inscrip);
rd_long(&item->flags);
rd_byte(&item->tval);
rd_byte(&item->tchar);
rd_short((int16u *) & item->p1);
rd_long((int32u *) & item->cost);
rd_byte(&item->subval);
rd_byte(&item->number);
rd_short(&item->weight);
rd_short((int16u *) & item->tohit);
rd_short((int16u *) & item->todam);
rd_short((int16u *) & item->ac);
rd_short((int16u *) & item->toac);
rd_bytes(item->damage, 2);
rd_byte(&item->level);
rd_byte(&item->ident);
rd_long(&item->flags2);
rd_short((int16u *) & item->timeout);
}
static void
rd_monster(mon)
register monster_type *mon;
{
rd_short((int16u *) & mon->hp);
if ((version_maj >= 2) && (version_min >= 6))
rd_short((int16u *) & mon->maxhp);
else {
/* let's fix the infamous monster heal bug -CWS */
mon->maxhp = mon->hp;
}
rd_short((int16u *) & mon->csleep);
rd_short((int16u *) & mon->cspeed);
rd_short(&mon->mptr);
rd_byte(&mon->fy);
rd_byte(&mon->fx);
rd_byte(&mon->cdis);
rd_byte(&mon->ml);
rd_byte(&mon->stunned);
rd_byte(&mon->confused);
if ((version_maj >= 2) && (version_min >= 6))
rd_byte((int8u *) & mon->monfear);
else
mon->monfear = 0; /* this is not saved either -CWS */
}